package com.caregiver.watch.business.care.service.impl;

import com.caregiver.watch.business.care.dao.PackageInfoDao;
import com.caregiver.watch.business.care.enums.PackageEffectivenessStatusEnum;
import com.caregiver.watch.business.care.enums.PackageTypeEnum;
import com.caregiver.watch.business.care.model.bo.AlertCountBo;
import com.caregiver.watch.business.care.model.dto.OpenHealthAlertParam;
import com.caregiver.watch.business.care.model.dto.QueryWarningHistoryParam;
import com.caregiver.watch.business.care.model.po.PackageInfo;
import com.caregiver.watch.business.care.model.po.UserAlertRecord;
import com.caregiver.watch.business.care.model.po.UserPackageOrder;
import com.caregiver.watch.business.care.model.vo.AlertCountVo;
import com.caregiver.watch.business.care.model.vo.AlertCountVo.AlertCount;
import com.caregiver.watch.business.care.model.vo.BoughtPackageInfoVo;
import com.caregiver.watch.business.care.model.vo.HealthAlertPackageInfoVo;
import com.caregiver.watch.business.care.model.vo.HealthAlertPackageVo;
import com.caregiver.watch.business.care.model.vo.HealthAlertServiceInfoVo;
import com.caregiver.watch.business.care.model.vo.OpenHealthAlertVo;
import com.caregiver.watch.business.care.model.vo.WarningHistoryVo;
import com.caregiver.watch.business.care.service.CareRecipientService;
import com.caregiver.watch.business.care.service.HealthAlertService;
import com.caregiver.watch.business.care.service.UserAlertRecordService;
import com.caregiver.watch.business.care.service.UserPackageOrderService;
import com.caregiver.watch.business.user.model.bo.CareRecipientNameBo;
import com.caregiver.watch.business.user.model.po.UserCareRecipient;
import com.caregiver.watch.business.user.utils.UserInfoUtils;
import com.caregiver.watch.common.exception.business.BusinessException;
import com.caregiver.watch.common.helper.SequentialNoHelper;
import com.caregiver.watch.common.helper.TransactionalHelper;
import com.caregiver.watch.common.utils.collection.ListUtils;
import com.caregiver.watch.common.utils.number.IntegerUtils;
import com.caregiver.watch.common.utils.page.PageUtils;
import com.caregiver.watch.common.utils.time.DateUtils;
import com.caregiver.watch.thirdparty.api.WXPayUtility;
import com.caregiver.watch.thirdparty.model.dto.DirectAPIv3AppPrepayResponse;
import com.caregiver.watch.thirdparty.properties.WXPayProperties;
import com.caregiver.watch.thirdparty.model.dto.CommonPrepayRequest;
import com.caregiver.watch.thirdparty.model.dto.CommonPrepayRequest.*;
import com.github.pagehelper.Page;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static com.caregiver.watch.business.care.enums.OrderStatusEnum.PENDING_PAYMENT;
import static com.caregiver.watch.business.care.enums.PackageEffectivenessStatusEnum.EFFECTIVE;
import static com.caregiver.watch.business.care.enums.PackageTypeEnum.COUNT;
import static com.caregiver.watch.common.constant.NumberConstants.BIG_DECIMAL_HUNDRED;
import static com.caregiver.watch.common.constant.NumberConstants.MINUS_ONE;
import static com.caregiver.watch.common.constant.NumberConstants.ONE_LONG;
import static com.caregiver.watch.common.constant.NumberConstants.THIRTY;
import static com.caregiver.watch.common.constant.NumberConstants.ZERO;
import static com.caregiver.watch.common.utils.page.PageUtils.ORDER_BY_CREATE_TIME_DESC;

/**
 * @Description: 健康预警服务
 * @Author 疆戟
 * @Date 2025/10/10 23:11
 * @Version 1.0
 */
@AllArgsConstructor
@Service
@Slf4j
public class HealthAlertServiceImpl implements HealthAlertService {

    private final PackageInfoDao packageInfoDao;
    private final UserPackageOrderService userPackageOrderService;
    private final TransactionalHelper transactionalHelper;
//    private final WXPayService wxPayService;
    private final WXPayProperties wxPayProperties;
    private final UserAlertRecordService userAlertRecordService;
    private final CareRecipientService careRecipientService;

    @Override
    public HealthAlertServiceInfoVo queryUserHealthAlertInfo() {
        // 查询用户服务信息
        Long userId = UserInfoUtils.getUserId();
        // 是否存在已支付的订单
        List<UserPackageOrder> userPackageOrders = userPackageOrderService.queryEffectiveOrders(userId);
        // 获取生效中的套餐
        UserPackageOrder effectiveOrder = null;
        // 统计总守护天数 和 累计预警次数
        int totalGuardDays = 0;
        for (UserPackageOrder order : userPackageOrders) {
            PackageTypeEnum packageType = order.getPackageType();
            if (Objects.isNull(packageType)) {
                continue;
            }
            // 获取套餐生效状态
            PackageEffectivenessStatusEnum effectiveStatus = packageType.getEffectiveStatus(order);
            totalGuardDays = effectiveStatus.countGuardDays(order);
            // 生效中的套餐
            if (EFFECTIVE == effectiveStatus) {
                effectiveOrder = order;
                break;
            }
        }
        HealthAlertServiceInfoVo vo = new HealthAlertServiceInfoVo();
        if (Objects.nonNull(effectiveOrder)) {
            PackageTypeEnum packageType = effectiveOrder.getPackageType();
            vo.setIsOpenHealthWarning(Boolean.TRUE);
            vo.setIsFirstOpen(Boolean.FALSE);
            vo.setHealthWarningExpireTime(effectiveOrder.getExpireTime());
            vo.setPackageType(effectiveOrder.getPackageType());
            vo.setSupportDeviceNum(effectiveOrder.getSupportDeviceNum());
            vo.setTotalGuardDays(totalGuardDays);
            if (COUNT == packageType) {
                Integer totalWarningNum = IntegerUtils.ofNullable(effectiveOrder.getPackageValue());
                vo.setTotalWarningNum(totalWarningNum);
                vo.setSurplusWarningNum(totalWarningNum - IntegerUtils.ofNullable(effectiveOrder.getWarningCount()));
            } else {
                vo.setTotalWarningNum(MINUS_ONE);
                vo.setSurplusWarningNum(MINUS_ONE);
            }
            vo.setWarningNum(effectiveOrder.getWarningCount());
            return vo;
        }
        // 没有生效的订单
        vo.setIsOpenHealthWarning(Boolean.FALSE);
        // 查询是否首次开通
        vo.setIsFirstOpen(CollectionUtils.isEmpty(userPackageOrders));
        return vo;
    }

    @Override
    public HealthAlertPackageInfoVo queryHealthAlertPackageInfo() {
        // 查询所有套餐信息
        List<PackageInfo> packageInfos = packageInfoDao.selectAll();
        // 次数套餐
        List<PackageInfo> countPackageInfos = ListUtils.filter(packageInfos, packageInfo -> packageInfo.getPackageType() == COUNT);
        List<HealthAlertPackageVo> countPackageVos = ListUtils.map(countPackageInfos, packageInfo -> HealthAlertPackageVo.build(packageInfo));
        // 时间套餐
        List<PackageInfo> durationPackageInfos = ListUtils.filter(packageInfos, packageInfo -> packageInfo.getPackageType() != COUNT);
        List<HealthAlertPackageVo> subscribePackage = ListUtils.map(durationPackageInfos, packageInfo -> HealthAlertPackageVo.build(packageInfo));
        return HealthAlertPackageInfoVo.build(countPackageVos, subscribePackage);
    }

    @Override
    public List<BoughtPackageInfoVo> queryUserBoughtPackageList() {
        // 查询用户服务信息
        Long userId = UserInfoUtils.getUserId();
        List<UserPackageOrder> userPackageOrders = userPackageOrderService.queryEffectiveOrders(userId);
        return ListUtils.map(userPackageOrders, order -> BoughtPackageInfoVo.build(order));
    }

    @Override
    public OpenHealthAlertVo openHealthAlert(OpenHealthAlertParam param) {
        if (Objects.isNull(param.getPackageId())) {
            throw new BusinessException("套餐ID不能为空");
        }
        // 获取套餐信息
        PackageInfo packageInfo = packageInfoDao.selectById(param.getPackageId());
        if (Objects.isNull(packageInfo)) {
            log.error("[健康预警] 获取套餐信息失败，套餐ID：{}", param.getPackageId());
            throw new BusinessException("未知的套餐信息");
        }
        // 查询用户服务信息
        Long userId = UserInfoUtils.getUserId();
        PackageTypeEnum packageType = packageInfo.getPackageType();
        UserPackageOrder order = new UserPackageOrder();
        order.setOrderNo(SequentialNoHelper.generateNo(packageType.getPrefix(), userId));
        order.setUserId(userId);
        order.setOrderStatus(PENDING_PAYMENT.getCode());
        order.setTotalAmount(packageInfo.getPackagePrice());
        order.setPackageName(packageInfo.getPackageName());
        order.setPackageCode(packageInfo.getPackageCode());
        order.setPackagePrice(packageInfo.getPackagePrice());
        order.setPackageType(packageType);
        order.setPackageValue(packageInfo.getPackageValue());
        order.setPackageUnit(packageInfo.getPackageUnit());
        order.setSupportDeviceNum(packageInfo.getSupportDeviceNum());
        order.setOrderTime(LocalDateTime.now());
        return transactionalHelper.execute(() -> {
            boolean success = userPackageOrderService.saveOrder(order);
            // 插入成功 创建预支付的单
            String prepayId = null;
            if (success) {
                // 创建预支付订单
                prepayId = createPrepayOrder(order);
            }
            return OpenHealthAlertVo.build(prepayId, success);
        });
    }

    /**
     * 创建预支付订单
     * @param order
     * @return
     */
    private String createPrepayOrder(UserPackageOrder order) {
        CommonPrepayRequest request = new CommonPrepayRequest();
        request.appid = wxPayProperties.getAppId();
        request.mchid = wxPayProperties.getMchId();
        request.description = order.getPackageName();
        // 商户系统内部订单号
        request.outTradeNo = order.getOrderNo();
        // 计算出到期时间
        Integer expireTime = Optional.ofNullable(wxPayProperties.getExpireTime()).orElse(THIRTY);
        request.timeExpire = LocalDateTime.now().plusMinutes(expireTime).toString();
        // 异步通知地址
        request.notifyUrl = wxPayProperties.getNotifyUrl();
        request.supportFapiao = false;
        // 订单金额信息
        request.amount = new CommonAmountInfo();
        // 订单金额
        request.amount.total = order.getTotalAmount().multiply(BIG_DECIMAL_HUNDRED).longValue();
        request.amount.currency = "CNY";
        //
        request.detail = new CouponInfo();
        request.detail.costPrice = 608800L;
        request.detail.invoiceId = "微信123";
        request.detail.goodsDetail = new ArrayList<>();
        {
            GoodsDetail goodsDetailItem = new GoodsDetail();
            goodsDetailItem.merchantGoodsId = order.getPackageCode();
            goodsDetailItem.goodsName = order.getPackageName();
            goodsDetailItem.quantity = ONE_LONG;
            goodsDetailItem.unitPrice = order.getPackagePrice().multiply(BIG_DECIMAL_HUNDRED).longValue();
            request.detail.goodsDetail.add(goodsDetailItem);
        };
        request.settleInfo = new SettleInfo();
        request.settleInfo.profitSharing = false;
        try {
            DirectAPIv3AppPrepayResponse response = new DirectAPIv3AppPrepayResponse();
            log.info("[健康预警] 创建预支付订单成功，订单号：{}", response.prepayId);
            return response.getPrepayId();
        } catch (WXPayUtility.ApiException e) {
            log.error("[健康预警] 创建预支付订单失败，订单号：{}", request.outTradeNo);
            throw new BusinessException("创建预支付订单失败");
        }
    }

    @Override
    public Page<WarningHistoryVo> queryWarningHistory(QueryWarningHistoryParam param) {
        Long userId = UserInfoUtils.getUserId();
        LocalDateTime startDate = DateUtils.parseLocalDate(param.getStartTime(), LocalTime.MIN);
        LocalDateTime endDate = DateUtils.parseLocalDate(param.getEndTime(), LocalTime.MAX);
        // 获取预警历史
        Page<WarningHistoryVo> userAlertRecords = PageUtils.selectPage(param.getPageNum(),
                param.getPageSize(),
                () -> userAlertRecordService.queryWarningHistory(userId, param.getRecipientId(), startDate, endDate),
                data -> WarningHistoryVo.build(data),
                ORDER_BY_CREATE_TIME_DESC);
        List<Long> recipientIds = ListUtils.map(userAlertRecords, WarningHistoryVo::getRecipientId);
        List<UserCareRecipient> careRecipients = careRecipientService.queryUserCareRecipientByIds(userId, recipientIds);
        Map<Long, UserCareRecipient> recipientIdToCareRecipientMap = ListUtils.toMap(careRecipients, UserCareRecipient::getRecipientId);
        userAlertRecords.forEach(vo -> {
            UserCareRecipient userCareRecipient = recipientIdToCareRecipientMap.get(vo.getRecipientId());
            if (Objects.isNull(userCareRecipient)) {
                return;
            }
            vo.setRecipientName(userCareRecipient.getName());
            vo.setRecipientAvatar(userCareRecipient.getAvatarUrl());
        });
        return userAlertRecords;
    }

    @Override
    public AlertCountVo queryAlertCount(String startTime, String endTime) {
        Long userId = UserInfoUtils.getUserId();
        LocalDateTime startDate = DateUtils.parseLocalDate(startTime, LocalTime.MIN);
        LocalDateTime endDate = DateUtils.parseLocalDate(endTime, LocalTime.MAX);
        // 查询全部被照护人名称
        List<CareRecipientNameBo> careUserNames = careRecipientService.queryCareRecipientName(userId);
        List<AlertCountBo> alertCountBos = userAlertRecordService.countAlerts(userId, startDate, endDate);
        Map<Long, Integer> recipientIdToAlertCountMap = ListUtils.toMap(alertCountBos, AlertCountBo::getRecipientId, AlertCountBo::getAlertCount);
        List<AlertCount> alertCounts = ListUtils.map(careUserNames, careUserName -> {
            AlertCount alertCount = new AlertCount();
            alertCount.setRecipientId(careUserName.getRecipientId());
            alertCount.setRecipientName(careUserName.getRecipientName());
            alertCount.setAlertCount(recipientIdToAlertCountMap.getOrDefault(careUserName.getRecipientId(), ZERO));
            return alertCount;
        });
        return AlertCountVo.build(alertCounts);
    }
}
